using System;
using System.Diagnostics;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace AzureContrib.WindowsAzure.Diagnostics
{
	/// <summary>
	/// A <see cref="BrokeredMessage"/> to trace to a given <see cref="Category"/> for a given <see cref="Switch"/>
	/// </summary>
	public class TraceBrokeredMessage
	{
		/// <summary>
		/// The names used as keys <see cref="BrokeredMessage.Properties"/>.
		/// </summary>
		public static class ServiceBusMessagingNames
		{
			/// <summary>
			/// <see cref="TraceType"/>
			/// </summary>
			public const string TraceType = "TraceType";

			/// <summary>
			/// <see cref="TraceLevel"/>
			/// </summary>
			public const string TraceLevel = "TraceLevel";

			/// <summary>
			/// A <see cref="string"/> used for a tracer switch name.
			/// </summary>
			public const string Switch = "Switch";

			/// <summary>
			/// <see cref="Role.Name"/>
			/// </summary>
			public const string RoleName = "Role.Name";

			/// <summary>
			/// <see cref="RoleInstance.Id"/>
			/// </summary>
			public const string InstanceId = "RoleInstance.Id";

			/// <summary>
			/// <see cref="RoleEnvironment.DeploymentId"/>
			/// </summary>
			public const string DeploymentId = "RoleEnvironment.DeploymentId";
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TraceBrokeredMessage"/> class. 
		/// </summary>
		/// <param name="traceType">
		/// <see cref="TraceType"/>
		/// </param>
		/// <param name="traceMessage">
		/// The <see cref="TraceMessage"/> being traced.
		/// </param>
		/// <param name="roleName">
		/// The name of the role doing the tracing. 
		/// <seealso cref="Role.Name"/>
		/// </param>
		/// <param name="instanceId">
		/// The id of the current instance tracing. <see cref="RoleInstance.Id"/>
		/// </param>
		/// <param name="deploymentId">
		/// The id of the current Windows Azure deployment. 
		/// <seealso cref="RoleEnvironment.DeploymentId"/>
		/// </param>
		public TraceBrokeredMessage(
			TraceType traceType,
			TraceMessage traceMessage,
			string roleName, string instanceId, string deploymentId)
		{
			TraceType = traceType;
			Category = traceMessage.Category;
			Switch = traceMessage.Switch;
			Message = traceMessage.Message;
			RoleName = roleName;
			InstanceId = instanceId;
			DeploymentId = deploymentId;
		}

		/// <summary>
		/// <see cref="TraceType"/>
		/// </summary>
		public TraceType TraceType { get; set; }

		/// <summary>
		/// The <see cref="Category"/> for this trace message.
		/// </summary>
		public string Category { get; set; }

		/// <summary>
		/// The identifying switch we trace from.
		/// </summary>
		public string Switch { get; set; }

		/// <summary>
		/// The message traced.
		/// </summary>
		public string Message { get; set; }

		/// <summary>
		/// The unique name of the role we're p
		/// </summary>
		public string RoleName { get; set; }

		/// <summary>
		///
		/// </summary>
		public string InstanceId { get; set; }

		/// <summary>
		///
		/// </summary>
		public string DeploymentId { get; set; }

		/// <summary>
		/// Turn a <see cref="TraceBrokeredMessage"/> into a <see cref="BrokeredMessage"/>.
		/// </summary>
		/// <param name="brokeredMessage">The <see cref="TraceBrokeredMessage"/> to convert.</param>
		/// <returns>A <see cref="BrokeredMessage"/> created from the incomming <paramref name="brokeredMessage"/>.</returns>
		public static implicit operator TraceBrokeredMessage(BrokeredMessage brokeredMessage)
		{
			TraceType traceType = (TraceType)Enum.Parse(typeof(TraceType), brokeredMessage.Properties[ServiceBusMessagingNames.TraceType].ToString());

			TraceLevel traceLevel = (TraceLevel)Enum.Parse(typeof(TraceLevel), brokeredMessage.Properties[ServiceBusMessagingNames.TraceLevel].ToString());
			string @switch = brokeredMessage.Properties[ServiceBusMessagingNames.Switch].ToString();
			string message = brokeredMessage.GetBody<string>();
			TraceMessage traceMessage = new TraceMessage(traceLevel, @switch, message);

			string roleName = brokeredMessage.Properties[ServiceBusMessagingNames.RoleName].ToString();
			string instanceId = brokeredMessage.Properties[ServiceBusMessagingNames.InstanceId].ToString();
			string deploymentId = brokeredMessage.Properties[ServiceBusMessagingNames.DeploymentId].ToString();

			return new TraceBrokeredMessage(traceType, traceMessage, roleName, instanceId, deploymentId);
		}

		/// <summary>
		/// Turn a <see cref="TraceBrokeredMessage"/> into a <see cref="BrokeredMessage"/>.
		/// </summary>
		/// <param name="traceBrokeredMessage">The <see cref="TraceBrokeredMessage"/> to convert.</param>
		/// <returns>A <see cref="BrokeredMessage"/> created from the incomming <paramref name="traceBrokeredMessage"/>.</returns>
		public static implicit operator BrokeredMessage(TraceBrokeredMessage traceBrokeredMessage)
		{
			var brokeredMessage = BrokeredMessage.CreateMessage(traceBrokeredMessage.Message);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.TraceType, traceBrokeredMessage.TraceType);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.TraceLevel, traceBrokeredMessage.Category);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.Switch, traceBrokeredMessage.Switch);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.RoleName, traceBrokeredMessage.RoleName);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.InstanceId, traceBrokeredMessage.InstanceId);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.DeploymentId, traceBrokeredMessage.DeploymentId);
			return brokeredMessage;
		}
	}
}